<?php
include_once "db_config.php";
class DbModel{

	public $connection;
	public $errors = array();
	
	public function __construct(){

		// create mysql connection and related stuff
		$this->connection = mysql_connect(DB_SERVER . ":" . DB_PORT, DB_USER, DB_PASS) or die("Error connecting to DB server");
		mysql_select_db(DB_DATABASE) or die("Database not found.");
		mysql_query("SET NAMES " . DB_ENCODING);

		// init stuff
		if (!$this->table_name){
			$this->table_name = preg_replace('/^db_/', '', class2file(get_class($this)));
		}
		if(!$this->order){
			$this->order = "id";
		}
	}

	private function _parseOptions($options){
		// SELECT
		$sql_select = "SELECT *";
		if($options["select"]){
			$sql_select = "SELECT " . (is_array($options["select"]) ? implode(", ", $options["select"]) : $options["select"]);
		}

		// FROM
		$sql_from = "FROM " . ($options["from"] ? $options["from"] : $this->table_name);

		// WHERE
		$sql_where = "";
		if ($options["conditions"]){
			$sql_where = "WHERE 1 ";
			if(is_array($options["conditions"])){
				foreach($options["conditions"] as $k=>$v){
					$sql_where .= $this->_parseWhere($k,$v);
				}
			}else{
				$sql_where .= " AND " . $options["conditions"];
			}
		}

		// GROUP
		$sql_group = "";
		if($options["group"]){
			$sql_group = "GROUP BY " . (is_array($options["group"]) ? implode(", ", $options["group"]) : $options["group"]);
		}

		// ORDER
		$sql_order = "ORDER BY " . $this->order;
		if($options["order"]){
			$sql_order = "ORDER BY " . (is_array($options["order"]) ? implode(", ", $options["order"]) : $options["order"]);
		}

		// LIMIT
		$sql_limit = "";
		if($options["offset"]){
			if (!is_array($options["offset"])){
				$options["offset"] = array($options["offset"]);
			}
			$per_page = isset($options["offset"][1]) ? (int)$options["offset"][1] : ITEMS_PER_PAGE;
			$start = ((int)$options["offset"][0] - 1) * $per_page;
			$sql_limit = "LIMIT $start, $per_page";
		}

		return "$sql_select $sql_from $sql_where $sql_group $sql_order $sql_limit";
	}
	private function _parseWhere($k,$v,$glue="AND"){
		$sql_where = "";
		if(preg_match('/\s/', $k)){
			list($k, $tst) = explode(" ", $k, 2);
			$sql_where .= " $glue $k $tst $v";
		}else{
			if(preg_match('/^\d+$/', $k)){
				$sql_where .= " $glue $v";
			}elseif(strtolower($k)=="or" || strtolower($k)=="and"){
				$sql_where .= " AND (" . (strtolower($k)=="or" ? 0 : 1);
				foreach($v as $m=>$n){
					$sql_where .= $this->_parseWhere($m,$n,$k);
				}
				$sql_where .= ") ";
			}else{
				$sql_where .= is_array($v) ? " $glue $k IN ('".implode("','", $v)."')" : " $glue $k = '$v'";
			}
		}
		return $sql_where;
	}

	public function query($sql){
		$ret = false;
		if($res = mysql_query($sql)){
			$ret = array();
			while($r = mysql_fetch_assoc($res)){
				$ret[] = $r;
			}
		}

		if($ret === false){
			$this->error_log($sql);
			$ret = array();
		}

		return $ret;
	}

	private function _query($options){
		return $this->query($this->_parseOptions($options));
	}

	public function find($options=array()){
		return $this->_query($options);
	}

	public function row($options=array()){
		$options["offset"] = array(1, 1);
		list($ret) = $this->_query($options);
		return count($ret)>0 ? $ret : array();
	}
	public function field($field, $options=array()){
		$options["select"] = $field;
		$row = $this->row($options);
		
		if(preg_match('/ as `?(.*?)`?/', $field)){
			preg_match_all('/ as `?([a-z0-9]+)`?/i', $field, $matches);
			$field = $matches[1][0];
		}
		
		return $row[$field];
	}

	public function count($options=array()){
		return $this->field("COUNT(*) as `cnt`", $options);
	}
	
	public function indexed($options=array(), $value="id", $label="name"){
		$res = $this->_query($options);
		$ret = array();
		foreach($res as $row){
			$ret[$row[$value]] = $row[$label];
		}
		return $ret;
	}

	public function exec($sql){
		$ret = mysql_query($sql, $this->connection) ? true : false;
		if(!$ret){
			$this->error_log($sql);
		}else{
			$this->error = (Object)array();
		}
		return $ret;
	}

	private function error_log($sql){
		$err = mysql_errno() . "# " . mysql_error() . ".";
		$this->errors[] = $err;
		Logger::add("Query: \"$sql\" triggered following error: " . $err);
	}
}